home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Cream of the Crop 1
/
Cream of the Crop 1.iso
/
PRINTER
/
JPSRC11.ARJ
/
JETBMP.C
next >
Wrap
C/C++ Source or Header
|
1991-08-04
|
37KB
|
1,140 lines
/*
* JET PAK - HP DeskJet and LaserJet series printer utilities
*
* JETBMP module - bitmap utility functions
*
* Version 1.1 (Public Domain)
*/
/* system include files */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/* application include files */
#include "jetfont.h"
#include "jetutil.h"
/*
* MODULE GLOBAL DATA
*/
/* bitmap outline edge information, including slope type */
#define SLOPE_NONE 0
#define SLOPE_NE 1
#define SLOPE_SE 2
#define SLOPE_SW 3
#define SLOPE_NW 4
typedef struct edge {
struct edge *nextedge;
UNSIGNEDINT sx;
UNSIGNEDINT sy;
SIGNEDINT dx;
SIGNEDINT dy;
UNSIGNEDBYTE slope;
} EDGE;
/* bitmap outline polygon - series of edges forming closed polygon */
typedef struct poly {
struct poly *nextpoly;
struct edge *firstedge;
} POLY;
/* lists of edges collected in first phase (four types) */
static EDGE *top_edges[MAX_CELL_HEIGHT] = { 0 };
static EDGE *right_edges[MAX_CELL_WIDTH] = { 0 };
static EDGE *bottom_edges[MAX_CELL_HEIGHT] = { 0 };
static EDGE *left_edges[MAX_CELL_WIDTH] = { 0 };
static UNSIGNEDBYTE bits[8] =
{
0x80, 0x40, 0x20, 0x10,
0x08, 0x04, 0x02, 0x01,
};
/*
* BITMAP SMOOTHING MACROS AND FUNCTIONS
*/
/* set a single bit */
#define bitset(p,w,h,x,y) \
{ \
if ((x) < (w) && (y) < (h)) \
*((p) + (y)*(((w) + 7)/8) + (x)/8) |= bits[(x)%8]; \
}
/* clear a single bit */
#define bitclear(p,w,h,x,y) \
{ \
if ((x) < (w) && (y) < (h)) \
*((p) + (y)*(((w) + 7)/8) + (x)/8) &= ~bits[(x)%8]; \
}
/* test a single bit */
#define bitat(p,w,h,x,y) \
( (x) < (w) \
&& (y) < (h) \
&& (*((p) + (y)*(((w) + 7)/8) + (x)/8) & bits[(x)%8]) != 0 \
)
static void bitmapclear(p,w,h)
UNSIGNEDBYTE *p; /* pointer to LJ format bitmap to be cleared */
UNSIGNEDINT w, h; /* dimensions of bitmap */
{
/*
* Clear the w by h bit bitmap at *p
*/
UNSIGNEDINT wb = (w + 7)/8;
while (h-- > 0)
for (w = 0; w < wb; w++)
*p++ = 0;
}
static void edge_smooth(p, w, h, ep, slope, cut)
UNSIGNEDBYTE *p; /* pointer to LJ format bitmap */
UNSIGNEDINT w, h; /* dimensions of LJ bitmap in dots */
EDGE *ep; /* pointer to edge position and direction */
UNSIGNEDBYTE slope; /* type of slope to be applied to edge */
SIGNEDINT cut; /* where to start cutting into the edge */
{
/*
* Smooth a single edge within bitmap.
*/
UNSIGNEDINT x, y;
switch(slope)
{
case SLOPE_NE:
if (cut >= 0)
return;
if (cut < ep->dy)
cut = ep->dy;
x = ep->sx;
for (y = ep->sy + ep->dy - cut; y > ep->sy + ep->dy; y--)
bitset(p, w, h, x, y-1);
break;
case SLOPE_SE:
if (cut <= 0)
return;
if (cut > ep->dy)
cut = ep->dy;
x = ep->sx - 1;
for (y = ep->sy + cut; y < ep->sy + ep->dy; y++)
bitset(p, w, h, x, y);
break;
case SLOPE_SW:
if (cut <= 0)
return;
if (cut > ep->dy)
cut = ep->dy;
x = ep->sx - 1;
for (y = ep->sy; y < ep->sy + ep->dy - cut; y++)
bitset(p, w, h, x, y);
break;
case SLOPE_NW:
if (cut >= 0)
return;
if (cut < ep->dy)
cut = ep->dy;
x = ep->sx;
for (y = ep->sy; y > ep->sy + cut; y--)
bitset(p, w, h, x, y-1);
break;
}
}
static void bitmap_free_all(firstpoly, cw, ch)
POLY *firstpoly; /* handle to bitmap outline tree data */
UNSIGNEDINT cw, ch; /* dimensions of LJ bitmap in dots */
{
/*
* Free up all the heap storage allocated during the bitmap
* smoothing process.
*/
POLY *pp;
EDGE *ep;
UNSIGNEDINT x, y;
/* free edge lists */
for (x = 0; x < cw; x++)
{
while ((ep = left_edges[x]) != NULL)
{
left_edges[x] = ep->nextedge;
free(ep);
}
while ((ep = right_edges[x]) != NULL)
{
right_edges[x] = ep->nextedge;
free(ep);
}
}
for (y = 0; y < ch; y++)
{
while ((ep = top_edges[y]) != NULL)
{
top_edges[y] = ep->nextedge;
free(ep);
}
while ((ep = bottom_edges[y]) != NULL)
{
bottom_edges[y] = ep->nextedge;
free(ep);
}
}
/* free outline trees */
while ((pp = firstpoly) != NULL)
{
while ((ep = pp->firstedge) != NULL)
{
pp->firstedge = ep->nextedge;
free(ep);
}
firstpoly = pp->nextpoly;
free(pp);
}
}
static int bitmap_trace(sbp, bmp, cw, ch)
UNSIGNEDBYTE *sbp; /* pointer to source (LJ) bitmap */
UNSIGNEDBYTE *bmp; /* pointer to smoothed bitmap mask */
UNSIGNEDINT cw, ch; /* dimensions of LJ bitmap in dots */
{
/*
* Find the edges within a bitmap, by scanning adjacent rows and
* columns. Four types of edges are identified - top, bottom, right
* and left.
*
* The boundary cases where a row or column being examined lies
* outside the regular bitmap are handled by pointing to the
* smoothed bitmap mask (known to be all zero at this point).
*
* The meaning of the variables is as follows:
*
* x, y: tracks the dot being examined
* bp1: points to the byte containing the first row/column
* bp2: points to the byte containing the second row/column
* mask1: mask for the first row/column (used with bp1)
* mask2: mask for the second row/column (used with bp2)
* offset: byte offset between bitmap rows
*/
EDGE **epp, *ep;
UNSIGNEDINT x, y, mask1, mask2, offset;
UNSIGNEDBYTE *bp1, *bp2;
/* get bitmap derived data used in subsequent calculations */
offset = (cw + 7)/8;
/* collect top edges */
bp1 = bmp; /* first row lies above real bitmap */
bp2 = sbp;
for (y = 0; y < ch; y++)
{
epp = &top_edges[y];
for (x = 0, mask1 = 0x80; x < cw; )
{
if ( ((*bp1 & mask1) == 0)
&& ((*bp2 & mask1) != 0) )
{
*epp = ep = (EDGE *)zalloc(sizeof(EDGE));
if (ep == NULL)
{
bitmap_free_all(NULL, cw, ch);
return(ERROR);
}
ep->sx = x;
ep->sy = y;
do {
ep->dx++;
x++;
if ((mask1 >>= 1) == 0)
{
mask1 = 0x80;
bp1++;
bp2++;
}
} while ( (x < cw)
&& ((*bp1 & mask1) == 0)
&& ((*bp2 & mask1) != 0) );
epp = &ep->nextedge;
}
else
{
x++;
if ((mask1 >>= 1) == 0)
{
mask1 = 0x80;
bp1++;
bp2++;
}
}
}
if (mask1 != 0x80)
{
/* bitmap width not an exact multiple of 8 */
bp1++;
bp2++;
}
if (y == 0)
bp1 = sbp;
}
/* collect bottom edges */
bp1 = sbp;
bp2 = sbp + offset;
for (y = 0; y < ch; y++)
{
if (y == (ch - 1))
bp2 = bmp; /* second row lies below real bitmap */
epp = &bottom_edges[y];
for (x = 0, mask1 = 0x80; x < cw; )
{
if ( ((*bp1 & mask1) != 0)
&& ((*bp2 & mask1) == 0) )
{
*epp = ep = (EDGE *)zalloc(sizeof(EDGE));
if (ep == NULL)
{
bitmap_free_all(NULL, cw, ch);
return(ERROR);
}
do {
ep->dx--;
x++;
if ((mask1 >>= 1) == 0)
{
mask1 = 0x80;
bp1++;
bp2++;
}
} while ( (x < cw)
&& ((*bp1 & mask1) != 0)
&& ((*bp2 & mask1) == 0) );
ep->sx = x;
ep->sy = y + 1;
epp = &ep->nextedge;
}
else
{
x++;
if ((mask1 >>= 1) == 0)
{
mask1 = 0x80;
bp1++;
bp2++;
}
}
}
if (mask1 != 0x80)
{
/* bitmap width not an exact multiple of 8 */
bp1++;
bp2++;
}
}
/* collect right edges */
mask1 = 0x80;
mask2 = 0x40;
for (x = 0; x < cw; x++)
{
bp1 = sbp + x/8;
if (x == (cw - 1))
bp2 = bmp; /* second row lies to the right of real bitmap */
else
bp2 = sbp + (x + 1)/8;
epp = &right_edges[x];
for (y = 0; y < ch; )
{
if ( ((*bp1 & mask1) != 0)
&& ((*bp2 & mask2) == 0) )
{
*epp = ep = (EDGE *)zalloc(sizeof(EDGE));
if (ep == NULL)
{
bitmap_free_all(NULL, cw, ch);
return(ERROR);
}
ep->sx = x + 1;
ep->sy = y;
do {
ep->dy++;
y++;
bp1 += offset;
bp2 += offset;
} while ( (y < ch)
&& ((*bp1 & mask1) != 0)
&& ((*bp2 & mask2) == 0) );
epp = &ep->nextedge;
}
else
{
y++;
bp1 += offset;
bp2 += offset;
}
}
mask1 = mask2;
if ((mask2 >>= 1) == 0)
mask2 = 0x80;
}
/* collect left edges */
mask1 = 0x01;
mask2 = 0x80;
for (x = 0; x < cw; x++)
{
if (x == 0)
bp1 = bmp; /* first row lies to the left of real bitmap */
else
bp1 = sbp + (x - 1)/8;
bp2 = sbp + x/8;
epp = &left_edges[x];
for (y = 0; y < ch; )
{
if ( ((*bp1 & mask1) == 0)
&& ((*bp2 & mask2) != 0) )
{
*epp = ep = (EDGE *)zalloc(sizeof(EDGE));
if (ep == NULL)
{
bitmap_free_all(NULL, cw, ch);
return(ERROR);
}
do {
ep->dy--;
y++;
bp1 += offset;
bp2 += offset;
} while ( (y < ch)
&& ((*bp1 & mask1) == 0)
&& ((*bp2 & mask2) != 0) );
ep->sx = x;
ep->sy = y;
epp = &ep->nextedge;
}
else
{
y++;
bp1 += offset;
bp2 += offset;
}
}
mask1 = mask2;
if ((mask2 >>= 1) == 0)
mask2 = 0x80;
}
return(OK);
}
int bitmap_smooth(sbp, bmp, cw, ch)
UNSIGNEDBYTE *sbp; /* pointer to source (LJ) bitmap */
UNSIGNEDBYTE *bmp; /* pointer to smoothed bitmap mask */
UNSIGNEDINT cw, ch; /* dimensions of LJ bitmap in dots */
{
/*
* Create smoothing data for a LaserJet bitmap. This is done
* by filling in a mask bitmap of the same dimensions as the
* source bitmap.
*
* A clear bit in the mask indicates the LaserJet bit should be
* to the left in the DeskJet bitmap; a set bit in the mask indicates
* the LaserJet bit should be to the right in the DeskJet bitmap.
*
* The LaserJet bitmap may itself be modified: it is sometimes
* necessary to clear two adjacent bits within the body of a
* character.
*
* The procedure for creating the smoothed bitmap mask is as
* follows:
*
* 1. The LJ bitmap is examined (by bitmap_trace()) to find the
* edge information. This is saved in four arrays (indexed by
* row or column) of pointers to linked lists of edges:
*
* EDGE top_edges[]
* EDGE right_edges[]
* EDGE bottom_edges[]
* EDGE left_edges[]
*
* EDGEs are expressed as a start position and an offset, with
* the convention that top edges point to the right, right edges
* point downwards, bottom edges point to the left and left
* edges point upwards, thus:
*
* ^---->
* |@@@@|
* |@@@@|
* |@@@@|
* <----V
*
* 2. The edges are then joined up, in sequence, into polygons.
* A linked list of POLYGON structures is constructed; each
* POLYGON points to a ring of EDGE structures (the first EDGE
* is pointed at by the POLYGON and also by the last EDGE in
* the ring).
*
* As EDGEs are assigned to a place in a POLYGON they are
* removed from the EDGE array linked lists, so that eventually,
* the EDGE array linked lists should be left empty.
*
* 3. A pass is made round the EDGES of each POLYGON to determine
* the type of slope associated with left and right edges that
* are separated by two 1 bit wide edges of the same type (the
* only edges of concern during the smoothing process)
*
* |@@@ @@@| @| |@
* |@@@ @@@| @| |@
* |@@@ @@@| @| |@
* <^@@ @@<V @V> ^>@
* |@@ @@| @@| |@@
* |@@ @@| @@| |@@
* <^@ @<V @@V> ^>@@
* |@ @| @@@| |@@@
* |@ @| @@@| |@@@
* |@ @| @@@| |@@@
*
* NW SW SE NE
*
* The type of slope is recorded in the EDGE structure.
*
* 4. Another pass is made round the EDGES of each POLYGON to
* actually apply the slope and create the smoothed bitmap mask.
* This involves not only applying the slope identified in step
* 3, but also extending that slope to adjacent left and
* right edges that don't have a slope identified.
*
* edge_smooth() is called to apply smoothing to a single
* edge at a defined position. This sets bits in the smoothed
* bitmap mask when the ideal position of a bit at the edge
* of the character lies to the right, rather than the left.
*
* 5. The smoothed bitmap mask is now completed by scanning
* each row of the bitmap. The source bitmap and the smoothed
* mask bitmap are considered together to envisage what the
* output DeskJet bitmap will look like.
*
* Adjacent set bits in the DeskJet bitmap are not allowed.
* So if a bit at a left edge needs to be to the right, bits
* in the body of a character are flipped over to the right,
* one by one.
*
* If adjacent set bits wind up at the right edge, and the
* right edge bit ideally should be on the left, two adjacent
* clear bits are created in the body of the character to
* allow this.
*
* As a special case of the above: if the character has no body
* (i.e. the bit on the left edge is adjacent to the bit on the
* right edge), the bit on the left edge is shifted back to the
* left. This is the only case where a bit cannot be placed at
* its "ideal" position in the output DeskJet bitmap.
*/
EDGE **pepp, **epp, *ep, *epm2, *epm1, *epp1, *epp2, *sep;
POLY **ppp, *pp, *firstpoly = NULL;
UNSIGNEDINT x, y;
struct edge *null_nep = NULL;
/* clear the mask bitmap */
bitmapclear(bmp, cw, ch);
/* 1. trace the edges of the shapes in the bitmap */
if (bitmap_trace(sbp, bmp, cw, ch) == ERROR)
return(ERROR);
/* 2. join edges into polygons */
ppp = &firstpoly;
for (x = 0; x < cw; x++)
{
while (*(epp = &left_edges[x]) != NULL)
{
/* unused edge - make first of polygon */
*ppp = (POLY *)zalloc(sizeof(POLY));
if (*ppp == NULL)
{
bitmap_free_all(firstpoly, cw, ch);
return(ERROR);
}
pepp = &(*ppp)->firstedge;
do {
/* move found edge from line list to polygon list */
*pepp = *epp;
*epp = (*epp)->nextedge;
/* search for next edge in polygon */
if ((*pepp)->dx == 0)
{
/* search top and bottom lists */
if (((*pepp)->sy+(*pepp)->dy) < ch)
{
epp = &top_edges[(*pepp)->sy+(*pepp)->dy];
while (*epp != NULL && (*epp)->sx != (*pepp)->sx)
epp = &(*epp)->nextedge;
}
else
{
epp = &null_nep;
}
if (*epp == NULL && ((*pepp)->sy+(*pepp)->dy) != 0)
{
epp = &bottom_edges[(*pepp)->sy+(*pepp)->dy-1];
while (*epp != NULL && (*epp)->sx != (*pepp)->sx)
epp = &(*epp)->nextedge;
}
}
else
{
/* search left and right lists */
if (((*pepp)->sx+(*pepp)->dx) < cw)
{
epp = &left_edges[(*pepp)->sx+(*pepp)->dx];
while (*epp != NULL && (*epp)->sy != (*pepp)->sy)
epp = &(*epp)->nextedge;
}
else
{
epp = &null_nep;
}
if (*epp == NULL && ((*pepp)->sx+(*pepp)->dx) != 0)
{
epp = &right_edges[(*pepp)->sx+(*pepp)->dx-1];
while (*epp != NULL && (*epp)->sy != (*pepp)->sy)
epp = &(*epp)->nextedge;
}
}
pepp = &(*pepp)->nextedge;
} while (*epp != NULL);
ppp = &(*ppp)->nextpoly;
*pepp = NULL;
}
}
/* 3. fill in the slope fields */
for (pp = firstpoly; pp != NULL; pp = pp->nextpoly)
{
epm2 = pp->firstedge;
epm1 = epm2->nextedge;
sep = ep = epm1->nextedge;
epp1 = ep->nextedge;
epp2 = epp1->nextedge;
do
{
if (epp2 == NULL)
epp2 = pp->firstedge;
if ( (epm1->dx == 1 && epp1->dx == 1)
|| (epm1->dx == -1 && epp1->dx == -1) )
{
if ( (ep->dy < 0 && epm2->dy < 0 && epp2->dy < 0)
|| (ep->dy > 0 && epm2->dy > 0 && epp2->dy > 0) )
{
if (epm1->dx == 1)
{
if (ep->dy < 0)
ep->slope = SLOPE_NE;
else
ep->slope = SLOPE_SE;
}
else
{
if (ep->dy < 0)
ep->slope = SLOPE_NW;
else
ep->slope = SLOPE_SW;
}
}
}
epm2 = epm1;
epm1 = ep;
ep = epp1;
epp1 = epp2;
epp2 = epp2->nextedge;
} while (ep != sep);
}
/* 4. apply slope where necessary */
for (pp = firstpoly; pp != NULL; pp = pp->nextpoly)
{
epm2 = pp->firstedge;
epm1 = epm2->nextedge;
sep = ep = epm1->nextedge;
epp1 = ep->nextedge;
epp2 = epp1->nextedge;
do
{
if (epp2 == NULL)
epp2 = pp->firstedge;
if (ep->dy != 0)
{
if (ep->slope != SLOPE_NONE)
{
/* edge has a slope that can be applied */
edge_smooth(bmp, cw, ch, ep, ep->slope, ep->dy/2);
}
else if (epm2->slope == SLOPE_NONE && epp2->slope != SLOPE_NONE)
{
/* apply slope of next edge along */
switch(epp2->slope)
{
case SLOPE_NE:
case SLOPE_SW:
edge_smooth(bmp, cw, ch, ep, epp2->slope, epp2->dy/2);
break;
case SLOPE_NW:
case SLOPE_SE:
edge_smooth(bmp, cw, ch, ep, epp2->slope, ep->dy - (epp2->dy - epp2->dy/2));
break;
}
}
else if (epm2->slope != SLOPE_NONE && epp2->slope == SLOPE_NONE)
{
/* apply slope of previous edge */
switch(epm2->slope)
{
case SLOPE_NW:
case SLOPE_SE:
edge_smooth(bmp, cw, ch, ep, epm2->slope, epm2->dy/2);
break;
case SLOPE_NE:
case SLOPE_SW:
edge_smooth(bmp, cw, ch, ep, epm2->slope, ep->dy - (epm2->dy - epm2->dy/2));
break;
}
}
else if (epm2->slope == SLOPE_SW && epp2->slope == SLOPE_SE)
{
/* concave right edge - apply next and previous edge
slopes */
edge_smooth(bmp, cw, ch, ep, epm2->slope, ep->dy - (epm2->dy - epm2->dy/2));
edge_smooth(bmp, cw, ch, ep, epp2->slope, ep->dy - (epp2->dy - epp2->dy/2));
}
else if (epm2->slope == SLOPE_NW && epp2->slope == SLOPE_NE)
{
/* convex left edge - apply next and previous edge
slopes */
edge_smooth(bmp, cw, ch, ep, epm2->slope, epm2->dy/2);
edge_smooth(bmp, cw, ch, ep, epp2->slope, epp2->dy/2);
}
}
epm2 = epm1;
epm1 = ep;
ep = epp1;
epp1 = epp2;
epp2 = epp2->nextedge;
} while (ep != sep);
}
/* 5. sort out adjacent set bits */
for (y = 0; y < ch; y++)
{
for (x = 0; x < cw; x++)
{
if ( bitat(sbp, cw, ch, x , y)
&& bitat(sbp, cw, ch, x+1, y)
&& bitat(bmp, cw, ch, x , y) )
{
/* adjacent pair of bits found */
if (bitat(sbp, cw, ch, x+2, y))
{
/* pair is not at the right edge of character - flip
right bit of pair to the right */
bitset(bmp, cw, ch, x+1, y);
}
else if (!bitat(bmp, cw, ch, x+1, y))
{
/* pair is at the right edge of character */
if (bitat(sbp, cw, ch, x-1, y))
{
/* create two adjacent clear bits in the body
of the character */
bitclear(sbp, cw, ch, x, y);
bitclear(bmp, cw, ch, x, y);
}
else
{
/* character is too thin to clear adjacent bits:
flip left bit of pair back to the left */
bitclear(bmp, cw, ch, x, y);
}
}
}
}
}
bitmap_free_all(firstpoly, cw, ch);
return(OK);
}
/*
* BITMAP CONVERSION FUNCTIONS
*/
int bitmap_compress(sbp, cw, ch, dbp, dsize)
UNSIGNEDBYTE *sbp; /* pointer to source (normal) bitmap */
UNSIGNEDINT cw, ch; /* dimensions of bitmap in dots */
UNSIGNEDBYTE *dbp; /* pointer to destination (compressed) bitmap */
UNSIGNEDINT dsize; /* maximum available space for destination bitmap */
{
/*
* Compress a DJ bitmap from normal bitmap format to zero byte
* compression format. The conversion is done by columns from
* left to right; within that, by rows from top to bottom. The
* meaning of the variables is as follows:
*
* x, y: tracks the dot being converted
* sbp2: points to the source byte containing the dot being converted
* smask: source mask for the dot being converted (used with sbp2)
* soffset: byte offset between rows of the source bitmap
* dbp2: points to the destination data byte containing the dot being converted
* dmask1: mask for the destination flag byte (used with dbp)
* dmask2: mask for the destination data byte (used with dbp2)
*
* The total number of bytes required to encode the output bitmap
* is returned.
*/
UNSIGNEDINT x, y, smask;
UNSIGNEDBYTE *sbp2;
UNSIGNEDINT dmask1, dmask2, soffset;
register UNSIGNEDBYTE *dbp2;
/* check sufficient space is available */
if ((cw + cw*((ch + 7)/8)) > dsize)
return(ERROR);
dbp2 = dbp + cw;
/* get the byte offset between rows of the source bitmap */
soffset = (cw + 7)/8;
for (x = 0; x < cw; x++)
{
sbp2 = sbp + x/8;
smask = bits[x%8];
*dbp = 0;
for (y = 0, dmask1 = 0x01; y < ch; dmask1 <<= 1)
{
*dbp2 = 0;
for (dmask2 = 0x80; y < ch && dmask2 != 0; y++, dmask2 >>= 1)
{
if (*sbp2 & smask)
*dbp2 |= dmask2;
sbp2 += soffset;
}
if (*dbp2 != 0)
{
*dbp |= dmask1;
dbp2++;
}
}
dbp++;
}
return((int)(cw + (dbp2 - dbp)));
}
int bitmap_decompress(sbp, cw, ch, dbp, dsize)
UNSIGNEDBYTE *sbp; /* pointer to source (compressed) bitmap */
UNSIGNEDINT cw, ch; /* dimensions of bitmap in dots */
UNSIGNEDBYTE *dbp; /* pointer to destination (normal) bitmap */
UNSIGNEDINT dsize; /* maximum available space for destination bitmap */
{
/*
* Decompress a DJ bitmap from zero byte compression format to
* normal bitmap format. This function is the exact reverse of
* bitmap_compress(). The conversion is done by columns from
* left to right; within that, by rows from top to bottom. The
* meaning of the variables is as follows:
*
* x, y: tracks the dot being converted
* sbp2: points to the source data byte containing the dot being converted
* smask1: mask for the source flag byte (used with sbp)
* smask2: mask for the source data byte (used with sbp2)
* dbp2: points to the destination byte containing the dot being converted
* dmask: destination mask for the dot being converted (used with dbp2)
* doffset: byte offset between rows of the destination bitmap
*/
UNSIGNEDINT x, y, smask1, smask2;
UNSIGNEDBYTE *sbp2 = sbp + cw;
UNSIGNEDINT dmask, doffset;
register UNSIGNEDBYTE *dbp2;
/* get the byte offset between rows of the destination bitmap */
doffset = (cw + 7)/8;
/* check sufficient space is available */
if ((doffset*ch) > dsize)
return(ERROR);
for (x = 0; x < cw; x++)
{
dbp2 = dbp + x/8;
dmask = bits[x%8];
for (y = 0, smask1 = 0x01; y < ch; smask1 <<= 1)
{
if (smask1 == 0x100)
{
smask1 = 0x01;
sbp++;
}
for (smask2 = 0x80; y < ch && smask2 != 0; y++, smask2 >>= 1)
{
if ((*sbp & smask1) && (*sbp2 & smask2))
*dbp2 |= dmask;
else
*dbp2 &= ~dmask;
dbp2 += doffset;
}
if (*sbp & smask1)
sbp2++;
}
sbp++;
}
return(OK);
}
int bitmap_lj_to_dj(sbp, bmp, cw, ch, nl, pl, pr, dbp, dsize)
UNSIGNEDBYTE *sbp; /* pointer to source (LJ) bitmap */
UNSIGNEDBYTE *bmp; /* pointer to smoothed bitmap mask */
UNSIGNEDINT cw, ch; /* dimensions of LJ bitmap in dots */
UNSIGNEDINT nl; /* number of leading blank lines */
UNSIGNEDINT pl; /* number of pad columns on left */
UNSIGNEDINT pr; /* number of pad columns on right */
UNSIGNEDBYTE *dbp; /* pointer to destination (DJ compressed) bitmap */
UNSIGNEDINT dsize; /* maximum available space for destination bitmap */
{
/*
* Convert a bitmap from LJ format to DJ format. This function
* is similar to bitmap_compress() but does two extra things:
*
* It converts the bitmap from 300x300 resolution to 600x300
* resolution by inserting blank bits under the control of the
* 'bmp' bitmap mask which contains smoothing data.
*
* It adds 'nl' blank lines at the start of the destination
* bitmap before moving in the source bitmap. This is useful
* because the LJ bitmaps often need to be shifted down in the
* DJ bitmap.
*
* This routine assumes that ch will less than 64; fortunately this
* should always be the case since the DJ series cannot handle more
* than a 50 bit high stripe in a single pass.
*
* The meaning of the variables is as follows:
*
* x, y: tracks the dot being converted
* sbp2: points to the source byte containing the dot being converted
* smask: source mask for the dot being converted (used with sbp2)
* soffset: byte offset between rows of the source bitmap
* dbp2: points to the destination data byte containing the dot being converted
* dmask1: mask for the destination flag byte (used with dbp)
* dmask2: mask for the destination data byte (used with dbp2)
*
* The total number of bytes required to encode the output bitmap
* is returned.
*/
UNSIGNEDINT x, y, smask;
UNSIGNEDBYTE *sbp2;
UNSIGNEDBYTE *bmp2;
UNSIGNEDINT dmask1, dmask2, soffset;
register UNSIGNEDBYTE *dbp2;
/* check sufficient space is available */
if ((cw*2 + pl + pr + cw*((ch + 7)/8)) > dsize)
return(ERROR);
dbp2 = dbp + cw*2 + pl + pr;
ch += nl;
soffset = (cw + 7)/8;
/* add in blank columns to left of bitmap */
for (x = 0; x < pl; x++)
*dbp++ = 0;
for (x = 0; x < cw; x++)
{
/* do the left hand column */
sbp2 = sbp + x/8;
bmp2 = bmp + x/8;
smask = bits[x%8];
*dbp = 0;
for (y = 0, dmask1 = 0x01; y < ch; dmask1 <<= 1)
{
*dbp2 = 0;
for (dmask2 = 0x80; y < ch && dmask2 != 0; y++, dmask2 >>= 1)
{
if (y >= nl)
{
if ((*sbp2 ^ *bmp2) & smask)
*dbp2 |= dmask2;
sbp2 += soffset;
bmp2 += soffset;
}
}
if (*dbp2 != 0)
{
*dbp |= dmask1;
dbp2++;
}
}
dbp++;
/* do the right hand column */
sbp2 = sbp + x/8;
bmp2 = bmp + x/8;
smask = bits[x%8];
*dbp = 0;
for (y = 0, dmask1 = 0x01; y < ch; dmask1 <<= 1)
{
*dbp2 = 0;
for (dmask2 = 0x80; y < ch && dmask2 != 0; y++, dmask2 >>= 1)
{
if (y >= nl)
{
if ((*sbp2 & *bmp2) & smask)
*dbp2 |= dmask2;
sbp2 += soffset;
bmp2 += soffset;
}
}
if (*dbp2 != 0)
{
*dbp |= dmask1;
dbp2++;
}
}
dbp++;
}
/* add in blank columns to right of bitmap */
for (x = 0; x < pr; x++)
*dbp++ = 0;
return((int)(cw*2 + pl + pr + (dbp2 - dbp)));
}
int bitmap_dj_to_lj(sbp, cw, ch, nl, dbp, dsize)
UNSIGNEDBYTE *sbp; /* pointer to source (compressed) bitmap */
UNSIGNEDINT cw, ch; /* dimensions of bitmap in dots */
UNSIGNEDINT nl; /* number of skipped lines */
UNSIGNEDBYTE *dbp; /* pointer to destination (normal) bitmap */
UNSIGNEDINT dsize; /* maximum available space for destination bitmap */
{
/*
* Convert a bitmap from DJ format to LJ format. This function
* is similar to bitmap_decompress() but in addition:
*
* It converts the bitmap from 600x300 resolution to 300x300
* resolution by ORing together adjacent columns in the DJ
* bitmap.
*
* It skips 'nl' blank lines in the destination bitmap before
* starting the conversion.
*
* x, y: tracks the dot being converted
* sbp2: points to the source data byte containing the dot being converted
* smask1: mask for the source flag byte (used with sbp)
* smask2: mask for the source data byte (used with sbp2)
* dbp2: points to the destination byte containing the dot being converted
* dmask: destination mask for the dot being converted (used with dbp2)
* doffset: byte offset between rows of the destination bitmap
*/
UNSIGNEDINT x, y, smask1, smask2;
UNSIGNEDBYTE *sbp2 = sbp + cw;
UNSIGNEDINT dmask, doffset;
register UNSIGNEDBYTE *dbp2;
/* get the byte offset between rows of the destination bitmap */
doffset = (cw/2 + 7)/8;
/* check sufficient space is available */
if ((doffset*(ch + nl)) > dsize)
return(ERROR);
for (x = 0; x < cw; x++)
{
dbp2 = dbp + nl*doffset + (x/2)/8;
dmask = bits[(x/2)%8];
for (y = 0, smask1 = 0x01; y < ch; smask1 <<= 1)
{
if (smask1 == 0x100)
{
smask1 = 0x01;
sbp++;
}
for (smask2 = 0x80; y < ch && smask2 != 0; y++, smask2 >>= 1)
{
if ((*sbp & smask1) && (*sbp2 & smask2))
*dbp2 |= dmask;
dbp2 += doffset;
}
if (*sbp & smask1)
sbp2++;
}
sbp++;
}
return(OK);
}